﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 库位视图服务
    /// </summary>
    [Route("api/LoactionView")]
    [ApiDescriptionSettings("库位视图", Name = "LoactionView", Order = 111)]

    public class LoactionViewService : IDynamicApiController, ITransient
    {
        private readonly IRepository<WareLocation, MasterDbContextLocator> _wareLocationRep; //库位仓储
        private readonly IRepository<WareContainerVsMaterial, MasterDbContextLocator> _wareContainerVsMaterialRep; //容器与物料关系仓储
        private readonly IRepository<WareLocationVsContainer, MasterDbContextLocator> _wareLocationVsContainerRep; //库位与容器关系仓储
        private readonly IRepository<WareStock, MasterDbContextLocator> _wareStockRep; //库存仓储
        private readonly IRepository<WareContainer, MasterDbContextLocator> _wareContainerRep; //库存仓储
        private readonly IRepository<v_ware_location, MasterDbContextLocator> _v_ware_locationRep; //库位试图仓储
        private readonly IRepository<WareTask, MasterDbContextLocator> _wareTaskRep; //任务仓储

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="wareLocationRep"></param>
        /// <param name="wareContainerVsMaterialRep"></param>
        /// <param name="wareLocationVsContainerRep"></param>
        /// <param name="wareStockRep"></param>
        /// <param name="wareContainerRep"></param>
        /// <param name="v_ware_locationRep"></param>
        /// <param name="wareTaskRep"></param>
        public LoactionViewService(
            IRepository<WareLocation, MasterDbContextLocator> wareLocationRep,
            IRepository<WareContainerVsMaterial, MasterDbContextLocator> wareContainerVsMaterialRep,
            IRepository<WareLocationVsContainer, MasterDbContextLocator> wareLocationVsContainerRep,
            IRepository<WareStock, MasterDbContextLocator> wareStockRep,
            IRepository<WareContainer, MasterDbContextLocator> wareContainerRep,
            IRepository<v_ware_location, MasterDbContextLocator> v_ware_locationRep,
            IRepository<WareTask, MasterDbContextLocator> wareTaskRep
            )
        {
            _wareLocationRep = wareLocationRep;
            _wareContainerVsMaterialRep = wareContainerVsMaterialRep;
            _wareLocationVsContainerRep = wareLocationVsContainerRep;
            _wareStockRep = wareStockRep;
            _wareContainerRep = wareContainerRep;
            _v_ware_locationRep = v_ware_locationRep;
            _wareTaskRep = wareTaskRep;
        }
        #endregion

        /// <summary>
        /// 查询库位试图
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("View")]
        public async Task<LoactionViewOutput> View([FromQuery] LocationViewInput input)
        {
            var list = await _v_ware_locationRep.DetachedEntities
                  .Where(input.AreaID != 10, u => u.AreaID == input.AreaID)
                  .Where(!string.IsNullOrEmpty(input.WareTwoName), u => u.WareTwo == input.WareTwoName)
                  .Where(!string.IsNullOrEmpty(input.RowNo.ToString()), u => u.RowNo == input.RowNo)
                  .ToListAsync();

            //获取有多少排,列,层
            var RowNos = list.OrderBy(n => n.RowNo).Select(n => n.RowNo).Distinct().ToList();
            var ColumnNos = list.OrderByDescending(n => n.ColumnNo).Select(n => n.ColumnNo).Distinct();
            var LayerNo = list.OrderByDescending(n => n.LayerNo).Select(n => n.LayerNo).Distinct();

            // 空闲
            int kongxianNum = list.Where(z => z.LocationStatus == LocationStatusEnum.kongxian).Count();

            // 待入
            int dairuNum = list.Where(z => z.LocationStatus == LocationStatusEnum.dairu).Count();

            // 待出
            int daichuNum = list.Where(z => z.LocationStatus == LocationStatusEnum.daichu).Count();

            // 锁定
            int lockingNum = list.Where(z => z.IsLock == YesOrNot.Y).Count();

            // 存货
            int cunhuoNum = list.Where(z => z.LocationStatus == LocationStatusEnum.cunhuo && z.IsEmptyContainer == YesOrNot.N).Count();

            // 空托
            int emptyContainerNum = list.Where(z => z.LocationStatus == LocationStatusEnum.cunhuo && z.IsEmptyContainer == YesOrNot.Y).Count();

            // 巷道
            //var aisleList = list.Select(n => n.Aisle).Distinct();

            var locationDataList = new List<WareLocationData>();

            foreach (var row in RowNos)
            {
                var locationDataModel = new WareLocationData();
                locationDataModel.RowNo = row;
                locationDataModel.wareLocationColumnNos = new List<WareLocationColumnNos>();
                foreach (var lay in LayerNo)
                {
                    var wareLocationColumnNos = new WareLocationColumnNos();
                    wareLocationColumnNos.LayerNo = lay;
                    wareLocationColumnNos.locationDetailOutput = new List<LocationDetailOutput>();
                    foreach (var col in ColumnNos)
                    {
                        var wareLocationMdoel = list.Where(p => p.RowNo == row && p.LayerNo == lay && p.ColumnNo == col).FirstOrDefault();
                        if (wareLocationMdoel != null)
                        {
                            var locationDetail = new LocationDetailOutput()
                            {
                                Id = wareLocationMdoel.Id,
                                RowNo = wareLocationMdoel.RowNo,
                                ColumnNo = wareLocationMdoel.ColumnNo,
                                LayerNo = wareLocationMdoel.LayerNo,
                                LocationCode = wareLocationMdoel.Code,
                                Attribute = wareLocationMdoel.Attribute,
                                Heavy = wareLocationMdoel.Heavy,
                                IsLock = wareLocationMdoel.IsLock,
                                IsEmptyContainer = wareLocationMdoel.IsEmptyContainer,
                                LocationStatus = wareLocationMdoel.LocationStatus,
                            };
                            wareLocationColumnNos.locationDetailOutput.Add(locationDetail);
                            //wareLocationColumnNos.locationDetailOutput.Add(wareLocationMdoel.Adapt<LocationDetailOutput>());
                        }
                        else
                        {
                            wareLocationColumnNos.locationDetailOutput.Add(null);
                        }
                    }
                    locationDataModel.wareLocationColumnNos.Add(wareLocationColumnNos);
                }
                locationDataList.Add(locationDataModel);
            }

            return new LoactionViewOutput()
            {
                kongxian = kongxianNum, //空闲
                dairu = dairuNum, //待入
                daichu = daichuNum, //待出
                cunhuo = cunhuoNum, //存货
                locking = lockingNum, //锁定
                emptyContainerNum = emptyContainerNum, //空托
                wareLocationData = locationDataList
            };
        }


        /// <summary>
        /// 根据库区获取库区下对应的排
        /// </summary>
        /// <returns></returns>
        [HttpGet("AreaRow")]
        public async Task<List<int>> GetAreaRow([FromQuery] LocationRowsViewInput input)
        {
            return await _wareLocationRep.Where(p => p.AreaID == input.AreaID).OrderBy(u => u.RowNo).Select(n => n.RowNo)
                .Distinct().ToListAsync();
        }

        /// <summary>
        /// 查询库位明细
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("GetLocationDetail")]
        public async Task<LocationDetailOutput> GetLocationDetail([FromQuery] LocationDetailInput input)
        {
            var location = await _wareLocationRep.FirstOrDefaultAsync(z => z.Id == input.Id);

            // 根据库位编码查询入库任务
            var wareTask = await _wareTaskRep.DetachedEntities.Where(u => u.ToLocationCode == location.Code && u.TaskType == TaskType.In).OrderByDescending(u => u.CreatedTime).FirstOrDefaultAsync();

            // 根据库位信息查询库位与容器关系
            if (location.LocationStatus == LocationStatusEnum.cunhuo || location.LocationStatus == LocationStatusEnum.daichu)
            {
                // 库位与容器关系
                var wareLocationVsContainerModel = await _wareLocationVsContainerRep.DetachedEntities.FirstOrDefaultAsync(z => z.LocationId == location.Id
                && z.LocationVsContainerStatus == CommonStatus.ENABLE);

                // 容器与物料关系
                var wareContainerVsMaterialList = await _wareContainerVsMaterialRep.DetachedEntities
                    .Where(z => z.ContainerCode == wareLocationVsContainerModel.ContainerCode && z.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                // 根据项目编号、物料信息去重
                var materialDistinct = wareContainerVsMaterialList.Select(z => new
                {
                    z.ProjectCode,
                    z.Code,
                    z.Name,
                    z.SpecificationModel
                }).Distinct().ToList();

                // 输出结果
                var loactionMaterialDetails = new List<WareContainerVsMaterial>();
                foreach (var item in materialDistinct)
                {
                    var wareContainerVsMaterials = wareContainerVsMaterialList.Where(z => z.Code == item.Code
                    && z.Name == item.Name && z.SpecificationModel == item.SpecificationModel).ToList();

                    var loactionMaterialDetailModel = new WareContainerVsMaterial
                    {
                        ContainerId = wareContainerVsMaterials.FirstOrDefault().ContainerId,
                        ContainerCode = wareContainerVsMaterials.FirstOrDefault().ContainerCode,
                        MaterialId = wareContainerVsMaterials.FirstOrDefault().MaterialId,
                        BrandName = wareContainerVsMaterials.FirstOrDefault().BrandName,
                        XuHao = wareContainerVsMaterials.FirstOrDefault().XuHao,
                        InspectionMethod = wareContainerVsMaterials.FirstOrDefault().InspectionMethod,
                        Code = wareContainerVsMaterials.FirstOrDefault().Code,
                        Name = wareContainerVsMaterials.FirstOrDefault().Name,
                        SpecificationModel = wareContainerVsMaterials.FirstOrDefault().SpecificationModel,
                        Unit = wareContainerVsMaterials.FirstOrDefault().Unit,
                        BindQuantity = wareContainerVsMaterials.Sum(t => t.BindQuantity)
                    };
                    loactionMaterialDetails.Add(loactionMaterialDetailModel);
                }

                return new LocationDetailOutput
                {
                    Id = location.Id,
                    LocationCode = location.Code,
                    ContainerCode = wareLocationVsContainerModel.ContainerCode,
                    Attribute = location.Attribute,
                    IsLock = location.IsLock,
                    IsEmptyContainer = location.IsEmptyContainer,
                    LocationStatus = location.LocationStatus,
                    Heavy = location.Heavy,
                    CreatedTime = wareTask != null && location.LocationStatus == LocationStatusEnum.cunhuo ? wareTask.UpdatedTime?.ToString("yyyy-MM-dd HH:mm:ss") : "", //入库时间
                    LoactionMaterialDetails = loactionMaterialDetails
                };
            }
            else if (location.LocationStatus == LocationStatusEnum.dairu)
            {
                var wareLocationVsContainerModel = await _wareLocationVsContainerRep.DetachedEntities.FirstOrDefaultAsync(z => z.LocationId == location.Id
                && z.LocationVsContainerStatus == CommonStatus.DISABLE);

                // 库位对应的物料明细
                var loactionMaterialDetails = new List<WareContainerVsMaterial>();
                if (wareLocationVsContainerModel != null)
                {
                    // 容器与物料关系
                    var wareContainerVsMaterialList = await _wareContainerVsMaterialRep.DetachedEntities
                        .Where(z => z.ContainerCode == wareLocationVsContainerModel.ContainerCode && z.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                    // 根据项目编号、物料信息去重
                    var materialDistinct = wareContainerVsMaterialList.Select(z => new
                    {
                        z.Code,
                        z.Name,
                        z.SpecificationModel
                    }).Distinct().ToList();

                    // 输出结果
                    foreach (var item in materialDistinct)
                    {
                        var wareContainerVsMaterials = wareContainerVsMaterialList.Where(z => z.Code == item.Code
                        && z.Name == item.Name && z.SpecificationModel == item.SpecificationModel).ToList();

                        var loactionMaterialDetailModel = new WareContainerVsMaterial
                        {
                            ContainerId = wareContainerVsMaterials.FirstOrDefault().ContainerId,
                            ContainerCode = wareContainerVsMaterials.FirstOrDefault().ContainerCode,
                            MaterialId = wareContainerVsMaterials.FirstOrDefault().MaterialId,
                            BrandName = wareContainerVsMaterials.FirstOrDefault().BrandName,
                            XuHao = wareContainerVsMaterials.FirstOrDefault().XuHao,
                            InspectionMethod = wareContainerVsMaterials.FirstOrDefault().InspectionMethod,
                            Code = wareContainerVsMaterials.FirstOrDefault().Code,
                            Name = wareContainerVsMaterials.FirstOrDefault().Name,
                            SpecificationModel = wareContainerVsMaterials.FirstOrDefault().SpecificationModel,
                            Unit = wareContainerVsMaterials.FirstOrDefault().Unit,
                            BindQuantity = wareContainerVsMaterials.Sum(t => t.BindQuantity)
                        };
                        loactionMaterialDetails.Add(loactionMaterialDetailModel);
                    }
                }

                return new LocationDetailOutput
                {
                    Id = location.Id,
                    LocationCode = location.Code,
                    ContainerCode = wareLocationVsContainerModel != null ? wareLocationVsContainerModel.ContainerCode : "",
                    Attribute = location.Attribute,
                    IsLock = location.IsLock,
                    IsEmptyContainer = location.IsEmptyContainer,
                    LocationStatus = location.LocationStatus,
                    Heavy = location.Heavy,
                    CreatedTime = "", //入库时间
                    LoactionMaterialDetails = loactionMaterialDetails.Count() > 0 ? loactionMaterialDetails : null
                };
            }
            else
            {
                return new LocationDetailOutput
                {
                    Id = location.Id,
                    LocationCode = location.Code,
                    ContainerCode = "N/A",
                    Attribute = location.Attribute,
                    IsLock = location.IsLock,
                    IsEmptyContainer = location.IsEmptyContainer,
                    LocationStatus = location.LocationStatus,
                    Heavy = location.Heavy,
                    CreatedTime = "", //入库时间
                    LoactionMaterialDetails = null
                };
            }
        }

        /// <summary>
        /// 更新库位属性
        /// </summary>
        /// <returns></returns>
        [HttpPost("UpdateAttribute")]
        public async Task UpdateAttribute([FromBody] UpdateAttributeInput input)
        {
            var location = await _wareLocationRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (location == null) throw Oops.Oh("库位不存在");
            location.Attribute = input.Attribute;
            await _wareLocationRep.UpdateAsync(location);
        }

        /// <summary>
        /// 锁定库位
        /// </summary>
        /// <returns></returns>
        [HttpPost("LockLocation")]
        public async Task LockLocation([FromBody] UpdateLockInput input)
        {
            var location = await _wareLocationRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (location == null) throw Oops.Oh("库位不存在");
            location.IsLock = input.IsLock;
            await _wareLocationRep.UpdateAsync(location);
        }

        /// <summary>
        /// 置为空闲
        /// </summary>
        /// <returns></returns>
        [HttpPost("ChangeIdle")]
        [UnitOfWork]
        public async Task ChangeIdle([FromBody] LocationIdleInput input)
        {
            //查询库位信息
            var location = await _wareLocationRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (location == null) throw Oops.Oh("库位不存在");

            if (location.LocationStatus == LocationStatusEnum.cunhuo || location.LocationStatus == LocationStatusEnum.daichu)
            {
                //删除库位容器关系
                var locationVScontion = await _wareLocationVsContainerRep.FirstOrDefaultAsync(z => z.LocationCode == location.Code
                && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                if (locationVScontion == null) throw Oops.Oh("库位容器关系不存在");

                //删除库存
                var sockModeList = await _wareStockRep.Where(z => z.LocationCode == location.Code).ToListAsync();
                foreach (var item in sockModeList)
                {
                    item.LocationCode = "N/A";
                }
                await _wareStockRep.UpdateAsync(sockModeList);


                //修改托盘状态
                var container = await _wareContainerRep.FirstOrDefaultAsync(z => z.Code == locationVScontion.ContainerCode);
                if (container != null)
                {
                    container.ContainerStatus = ContainerStatusEnum.zupan;
                    await _wareContainerRep.UpdateAsync(container);
                }

                await _wareLocationVsContainerRep.DeleteAsync(locationVScontion);
            }

            //修改库位为空闲
            location.LocationStatus = LocationStatusEnum.kongxian;

            await _wareLocationRep.UpdateAsync(location);
        }
    }
}
